package org.jprobe.utils;

import java.io.File;
import java.io.IOException;
import java.io.PipedWriter;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import org.jprobe.reflect.classpath.ClassEntry;
import org.jprobe.reflect.classpath.ClassPathReader;

/**
 * Java tools class
 * @author Hussain Al-Mutawa
 * @version 1.0
 */
public final class JavaTools {
	/** this class can not be initialized **/
	private JavaTools(){super();}

//	/** <code>./src</code> folder **/
//	public transient static File SRC = new File("./src");
//	/** <code>./bin</code> folder **/
//	public transient static File BIN = new File("./bin");
//	/** <code>./tmp</code> folder **/
//	public transient static File TMP = new File("./tmp");

	/**
	 * compiles a single java file
	 *
	 * @param src the source folder
	 * @param dst the destination folder
	 * @param javaFile the java file to be compiled
	 * @throws IOException
	 */
	public static Class<?> compile(final File src,final File dst,final File javaFile) throws IOException{
		//		if(!javaFile.exists()){
		//			throw new FileNotFoundException("The file [" + javaFile.getAbsolutePath() + "] can not be found" );
		//		}
		final StringBuffer buffer = new StringBuffer("\n========================\nCompiling class failed\n========================\n");
		try{
			//make the destination directory if not created yet
			dst.mkdirs();

			//javac equivalent command
			com.sun.tools.javac.Main.compile(new String[]{"-nowarn","-d",dst.getAbsolutePath(),javaFile.getAbsolutePath()},
					new PrintWriter(new PipedWriter(){
						@Override
						public void write(final char[] cbuf, final int off, final int len) {
							buffer.append(cbuf,off,len);
						}
					}, true)
			);

			if(buffer.toString().contains("error")){
				throw new IOException();
			}

			//to make sure the class has been compiled successfully
			final String className = javaFile.getName().replace(".java","");
			final String packageName = RegExUtils.extract(IOUtils.readFromFileSys(javaFile.getAbsolutePath()),RegExUtils.PACKAGE,2).trim();
			ClassPathReader.instance.addClassPathUrlToSystemClassLoader(dst);
			final Class<?>clazz=ClassPathReader.getClassloader().loadClass((packageName==RegExUtils.EMPTY?RegExUtils.EMPTY:packageName+'.')+className);
			ClassPathReader.instance.addClassToCLASSPATH(new ClassEntry(dst.getCanonicalPath(),clazz));
			return clazz;

		}catch(final Exception exp){
			throw new IOException(buffer.toString(),exp);
		}
	}

//	/*
//	 * loads a class from file system
//	 * @param buildDir - the directory which hold binary classes, usually <code>./bin</code>
//	 * @param classBinaryName - the <a href='http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html#name'>binary name</a> of the class
//	 * @return class loaded in the CLASSPATH
//	 * @throws MalformedURLException if the build directory does not exist, malformed, or invalid
//	 * @throws ClassNotFoundException if the class has not been compiled yet, not exists in the build directory as specified by the class <a href='http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html#name'>binary name</a>
//	 */
//	public static Class<?> loadClassByURL(final File buildDir,final String classBinaryName) throws MalformedURLException, ClassNotFoundException{
//		return ClassPathReader.getClassloader().loadClass(classBinaryName);
//	}
}
